﻿using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

/*********************************************************
 * 命名空间 Simple.SnowFlake
 * 接口名称 Woker
 * 开发人员：11920
 * 创建时间：2023/7/13 13:48:04
 * 描述说明：
 * 更改历史：
 * 
 * *******************************************************/
namespace Simple.SnowFlake
{
	public class Worker : IWorker
	{
		private static object oLock=new object();
		public Worker()
		{
			workId = 0; SetWorkId(workId);
		}
		static Worker()
		{
			Defaultlength = 63;
			DefaultTimelength = 42;
			WorkLength = 10;
			GetMove();
		}

		public static void SetWorkId(int workerId,int length=10)
		{
			if (workerId>Math.Pow(2,WorkLength))
			{
				throw new ArgumentException();
			}

			if (length>=63-DefaultTimelength)
			{
				throw new InvalidOperationException();
			}
			workId = workerId;
			if (WorkLength!=length)
			{
				WorkLength= length;
				GetMove();
			}
			Max = (int)Math.Pow(2, Defaultlength - DefaultTimelength - WorkLength);
		}
		private static void GetMove()
		{
			LeftMoveTimeLength = Defaultlength - DefaultTimelength;
			LeftMoveWorkLength = LeftMoveTimeLength - WorkLength;
			DateTimeExtension.SetYearLength(11);
		}

		private static int count;
		private static int Defaultlength;
		private static int DefaultTimelength;
		private static int WorkLength;
		private static int Max;


		private static int LeftMoveWorkLength;
		private static int LeftMoveTimeLength;

		private static int workId;

		private static readonly object countLock = new object();

		public async Task<long> NextIdAsync()
		{
			return await Task.Run(() =>
			{
				return NextId();
			});

		}

		public long NextId()
		{
			    return GetId();
		}

		public static long GetId()
		{
			long Id = 0;
			var timeTickes = DateTime.Now.GetTimeTicks();
			var temp = GetCount();
			Id = (timeTickes << LeftMoveTimeLength | (long)workId << LeftMoveWorkLength | (long)temp);
			return Id;
		}

		public static IWorker Builder()
		{
			return new Worker();
		} 

		private static int GetCount()
		{
			int temp = 0;
			lock (countLock)
			{
				if (count == Max)
				{
					count = 0;
				}
				else
				{
					count++;
					temp = count;
				}
			}
			return temp;
		}
	}
}
